package cn.hoichun.news.Service.Impl;

import cn.hoichun.news.Domain.Article;
import cn.hoichun.news.Domain.Rating;
import cn.hoichun.news.Mapper.ArticleMapper;
import cn.hoichun.news.Mapper.ScoreMapper;
import cn.hoichun.news.Service.IArticleService;
import cn.hoichun.news.Util.Random;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Hoichun
 */
@Service
public class ArticleServiceImpl implements IArticleService {

    private final ArticleMapper articleMapper;
    private final ScoreMapper scoreMapper;

    public ArticleServiceImpl(ArticleMapper articleMapper, ScoreMapper scoreMapper) {
        this.articleMapper = articleMapper;
        this.scoreMapper = scoreMapper;
    }
//    int D;
//    private final int U = 2000;


    @Override
    public List<Article> getRandomArticles(int pageSize) {
        List<Article> articleList = new ArrayList<>();
        for (int n : new Random().randomCommon(articleMapper.getCountArticles(), pageSize)) {
            articleList.add(this.getArticleById(n));
        }
        return articleList;
    }

    @Override
    public Article getArticleById(int id) {
        return articleMapper.getArticleById(id);
    }

    @Override
    public List<Article> searchArticlesUsingLike(List<String> wordList) {
        return articleMapper.getArticlesBySearchWordLike(wordList);
    }

    @Override
    public List<Article> searchArticlesUsingIndexWordOderBy(
            List<String> wordList,
            String orderMode,
            int size,
            int articleId
    ) {
   /*     List<Article> articleList = new ArrayList<>();
        HashMap<String, Double> wightMap = new HashMap<>();
        if ("bayes".equals(orderMode)) {

            D = articleMapper.getArticleWordTotalCount();
            HashMap<String, Double> wdMap = ToMap.toMap(articleMapper.getFreqByWords(wordList));
            HashMap<String, Double> iddMap = ToMap.toMap(articleMapper.getArticleIdAndWordFreqBySearchWord(
                    wordList
            ));
            HashMap<String, Double> wordBayesMap = ToMap.toMap(articleMapper.getValuesByIdWord(wordList, orderMode));
            for (MyMap.Entry<String, Double> entry : iddMap.entrySet()) {
                for (String word : wordList) {
                    wightMap.put(
                            entry.getKey(),
                            wightMap.get(entry.getKey()) == null ? (wordBayesMap.get(entry.getKey() + word) == null ? Math.log10(
                                    ((U * wdMap.get(word)) / ((entry.getValue() + U) * D))) : wordBayesMap.get(entry.getKey() + word)) : wightMap.get(
                                    entry.getKey()) + (wordBayesMap.get(entry.getKey() + word) == null ? Math.log10(
                                    ((U * wdMap.get(word)) / ((entry.getValue() + U) * D))) : wordBayesMap.get(entry.getKey() + word))
                    );
                }
            }

            List<MyMap.Entry<String, Double>> list = new ArrayList<>(wightMap.entrySet());
            list.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));
            for (MyMap.Entry<String, Double> entry : list) {
                articleList.add(articleMapper.getArticleById(Integer.parseInt(entry.getKey())));
            }

            return articleMapper.getSumValueByWord(wordList, orderMode);
        } else if ("tfidf".equals(orderMode)) {
            return articleMapper.getSumValueByWord(wordList, orderMode);
        } else if ("freqs".equals(orderMode)) {
            return articleMapper.getSumValueByWord(wordList, orderMode);
        }*/
        return articleMapper.getSumValueByWord(wordList, orderMode, size, articleId);
    }

    @Override
    public List<Article> searchArticlesUsingFulltextIndex(String word) {
        return articleMapper.getArticlesByFulltextIndex(word);
    }

    @Override
    public String getArticleKeyword(int articleId) {
        return articleMapper.selectKeywordByArticleId(articleId);
    }

    @Override
    public List<Article> getArticlesByUserMatrix(int userId) {
        HashMap<String, Double> interestMap = new HashMap<>();
        for (Rating rating :
                scoreMapper.selectAllRatings()) {
            interestMap.put(rating.getUserId() + "," + rating.getArticleId(), rating.getInterest());
        }
        HashMap<String, Double> matrixMap = new HashMap<>();
        double xy, x2, y2;
        for (int j :
                scoreMapper.selectAllUserId()) {
            if (userId != j) {
                xy = x2 = y2 = 0.;
                for (Integer k :
                        scoreMapper.selectAllArticleId()) {
                    xy += (interestMap.getOrDefault(userId + "," + k, 0.)) * (interestMap.getOrDefault(
                            j + "," + k,
                            0.
                    ));
                    x2 += (interestMap.getOrDefault(userId + "," + k, 0.)) * (interestMap.getOrDefault(
                            userId + "," + k,
                            0.
                    ));
                    y2 += (interestMap.getOrDefault(j + "," + k, 0.)) * (interestMap.getOrDefault(j + "," + k, 0.));
                }
                matrixMap.put(String.valueOf(j), xy / (Math.sqrt(x2) * Math.sqrt(y2)));
            }
        }

        List<Map.Entry<String, Double>> list = new ArrayList<>(matrixMap.entrySet());
        list.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));
        List<Article> articleList = new ArrayList<>();
        HashMap<Integer, Boolean> recordMap = new HashMap<>();
        for (Map.Entry<String, Double> entry : list) {
            for (int i :
                    scoreMapper.selectArticleByUserId(Integer.parseInt(entry.getKey()))) {
                if (!interestMap.containsKey(userId + "," + i) && !recordMap.containsKey(i)) {
                    recordMap.put(i, true);
                    articleList.add(articleMapper.getArticleById(i));
                }
                if (articleList.size() >= 10) {
                    return articleList;

                }
            }
        }
        return articleList;
    }
}